package com.ruoyi.generator.util;

import com.ruoyi.common.config.Global;
import com.ruoyi.common.constant.Constants;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.generator.domain.ColumnInfo;
import com.ruoyi.generator.domain.ParamInfo;
import com.ruoyi.generator.domain.TableInfo;
import org.apache.velocity.VelocityContext;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 代码生成器 工具类
 *
 * @author ruoyi
 */
public class GenUtils
{
    /** 项目空间路径 */
    private static final String PROJECT_PATH = getProjectPath();

    /** mybatis空间路径 */
    private static final String MYBATIS_PATH = "src/main/resources/mybatis/mapper"; //src/main/resources/mybatis/mapper/

    /** html空间路径 */
    private static final String TEMPLATES_PATH = "main/resources/templates";

    /** 类型转换 */
    public static Map<String, String> javaTypeMap = new HashMap<String, String>();

    /** 类型转换 */
    public static Map<String, String> jdbcTypeMap = new HashMap<String, String>();

    /**
     * 设置列信息
     */
    public static List<ColumnInfo> transColums(List<ColumnInfo> columns)
    {
        // 列信息
        List<ColumnInfo> columsList = new ArrayList<>();
        for (ColumnInfo column : columns)
        {
            // 列名转换成Java属性名
            String attrName = StringUtils.convertToCamelCase(column.getColumnName());
            column.setAttrName(attrName);
            column.setAttrname(StringUtils.uncapitalize(attrName));
            column.setExtra(column.getExtra());

            // 列的数据类型，转换成Java类型
            String dataType = column.getDataType();
            String attrType = javaTypeMap.get(dataType);
            column.setAttrType(attrType);

            //jdbcType,决定resultMap中的jdbcType
            /*String jdbcType = null;
            String attrTypeLower = attrType.toLowerCase();
            if ("date".equals(attrTypeLower) && "date".equals(dataType)) {
                jdbcType = jdbcTypeMap.get("date");
            } else if ("date".equals(attrTypeLower) && "datetime".equals(dataType)) {
                jdbcType = jdbcTypeMap.get("datetime");
            } else if ("String".equals(attrTypeLower) && "time".equals(dataType)) {
                jdbcType = jdbcTypeMap.get("time");
            } else {
                jdbcType = jdbcTypeMap.get(attrTypeLower);
            }
            column.setJdbcType(jdbcType);*/

            columsList.add(column);
        }
        return columsList;
    }

    /**
     * 获取模板信息
     *
     * @return 模板列表
     */
    public static VelocityContext getVelocityContext(ParamInfo info)
    {
        // java对象数据传递到模板文件vm
        VelocityContext velocityContext = new VelocityContext();
//        String packageName = Global.getPackageName();
        String packageName = info.getPackageName();
        TableInfo table = info.getTableInfo();
        velocityContext.put("tableName", table.getTableName());
        velocityContext.put("tableComment", replaceKeyword(table.getTableComment()));
        velocityContext.put("primaryKey", table.getPrimaryKey());
        velocityContext.put("className", table.getClassName());
        velocityContext.put("classname", table.getClassname());
        velocityContext.put("moduleName", getModuleName(packageName));
        velocityContext.put("columns", table.getColumns());
        velocityContext.put("basePackage", getBasePackage(packageName));
        velocityContext.put("lastPackage", getLastPackage(packageName));
        velocityContext.put("package", packageName);
        velocityContext.put("author", Global.getAuthor());
        velocityContext.put("datetime", DateUtils.getDate());
        //点
        velocityContext.put("dot", ".");
        //左括号
        velocityContext.put("leftBracket", "(");
        //右括号
        velocityContext.put("rightBracket", ")");
        return velocityContext;
    }

    /**
     * 获取模板信息
     *
     * @return 模板列表
     */
    public static List<String> getTemplates()
    {
        List<String> templates = new ArrayList<String>();
        templates.add("vm/java/domainDO.java.vm");
        templates.add("vm/java/domainBO.java.vm");
        templates.add("vm/java/Api.java.vm");
        templates.add("vm/java/domainCreateRB.java.vm");
        templates.add("vm/java/domainLimitRB.java.vm");
        templates.add("vm/java/domainPageRB.java.vm");
        templates.add("vm/java/domainUpdateRB.java.vm");
        templates.add("vm/java/ControllerTest.java.vm");
        templates.add("vm/java/ServiceTest.java.vm");
        templates.add("vm/java/Mapper.java.vm");
        templates.add("vm/java/Service.java.vm");
        templates.add("vm/java/ServiceImpl.java.vm");
        templates.add("vm/java/Controller.java.vm");
        templates.add("vm/xml/Mapper.xml.vm");
        //templates.add("vm/html/list.html.vm");
        //templates.add("vm/html/add.html.vm");
        //templates.add("vm/html/edit.html.vm");
        //templates.add("vm/sql/sql.vm");
        return templates;
    }

    /**
     * 表名转换成Java类名
     */
    public static String tableToJava(String tableName)
    {
        String autoRemovePre = Global.getAutoRemovePre();
        String tablePrefix = Global.getTablePrefix();
        if (Constants.AUTO_REOMVE_PRE.equals(autoRemovePre) && StringUtils.isNotEmpty(tablePrefix))
        {
            tableName = tableName.replaceFirst(tablePrefix, "");
        }
        return StringUtils.convertToCamelCase(tableName);
    }

    /**
     * 获取文件名
     */
    public static String getFileName(String template, TableInfo table, String moduleName, String packageName)
    {
        //表名
        String tableName = table.getTableName();
        // 小写类名
        String classname = table.getClassname();

        // 大写类名
        String className = table.getClassName();
        String javaPath = getProjectPath(packageName); // src/main/java/com/lgong/worker/
        String mybatisPath = MYBATIS_PATH + "/" + className;
        String htmlPath = TEMPLATES_PATH + "/" + moduleName + "/" + classname;

        if (template.contains("Api.java.vm"))
        {
            return "api/" + javaPath + "api" + "/" + className + "Api.java";
        }
        if (template.contains("domainDO.java.vm"))
        {
            return "entity/" + javaPath + "domain" + "/" + className + "DO.java";
        }
        if (template.contains("domainBO.java.vm"))
        {
            return "entity/" + javaPath + "bo" + "/" + className + "BO.java";
        }
        if (template.contains("domainCreateRB.java.vm"))
        {
            return "api/" + javaPath + "api/dto/"+ table.getTableName() + "/" + className + "CreateRB.java";
        }
        if (template.contains("domainLimitRB.java.vm"))
        {
            return "api/" + javaPath + "api/dto/"+ table.getTableName() + "/" + className + "LimitRB.java";
        }
        if (template.contains("domainPageRB.java.vm"))
        {
            return "api/" + javaPath + "api/dto/"+ table.getTableName() + "/" + className + "PageRB.java";
        }
        if (template.contains("domainUpdateRB.java.vm"))
        {
            return "api/" + javaPath + "api/dto/"+ table.getTableName() + "/" + className + "UpdateRB.java";
        }
        if (template.contains("ControllerTest.java.vm"))
        {
            return "microsvr/" + javaPath.replace("main", "test") + "controller/" + className + "ControllerTest.java";
        }
        if (template.contains("ServiceTest.java.vm"))
        {
            return "microsvr/" + javaPath.replace("main", "test") + "service/" + className +  "ServiceTest.java";
        }

        if (template.contains("Mapper.java.vm"))
        {
            return "microsvr/" + javaPath + "mapper" + "/" + className + "Mapper.java";
        }

        if (template.contains("Service.java.vm"))
        {
            return "microsvr/" + javaPath + "service" + "/" + className + "Service.java";
        }

        if (template.contains("ServiceImpl.java.vm"))
        {
            return "microsvr/" + javaPath + "service" + "/impl/" + className + "ServiceImpl.java";
        }

        if (template.contains("Controller.java.vm"))
        {
            return "microsvr/" + javaPath + "controller" + "/" + className + "Controller.java";
        }

        if (template.contains("Mapper.xml.vm"))
        {
            return "microsvr/" + mybatisPath + "Mapper.xml";
        }

        if (template.contains("list.html.vm"))
        {
            return htmlPath + "/" + classname + ".html";
        }
        if (template.contains("add.html.vm"))
        {
            return htmlPath + "/" + "add.html";
        }
        if (template.contains("edit.html.vm"))
        {
            return htmlPath + "/" + "edit.html";
        }
        if (template.contains("sql.vm"))
        {
            return classname + "Menu.sql";
        }
        return null;
    }

    /**
     * 获取模块名
     *
     * @param packageName 包名
     * @return 模块名
     */
    public static String getModuleName(String packageName)
    {
        int lastIndex = packageName.lastIndexOf(".");
        int nameLength = packageName.length();
        String moduleName = StringUtils.substring(packageName, lastIndex + 1, nameLength);
        return moduleName;
    }

    public static String getBasePackage(String packageName)
    {
        int lastIndex = packageName.lastIndexOf(".");
        String basePackage = StringUtils.substring(packageName, 0, lastIndex);
        return basePackage;
    }

    public static String getLastPackage(String packageName) {
        int lastIndex = packageName.lastIndexOf(".") + 1;
        String basePackage = StringUtils.substring(packageName, lastIndex, packageName.length());
        return basePackage.substring(0, 1).toUpperCase() + basePackage.substring(1);
    }

    public static String getProjectPath()
    {
        String packageName = Global.getPackageName();
        StringBuffer projectPath = new StringBuffer();
        projectPath.append("src/main/java/");
        projectPath.append(packageName.replace(".", "/"));
        projectPath.append("/");
        return projectPath.toString();
    }

    public static String getProjectPath(String packageName)
    {
        StringBuffer projectPath = new StringBuffer();
        projectPath.append("src/main/java/");
        projectPath.append(packageName.replace(".", "/"));
        projectPath.append("/");
        return projectPath.toString();
    }

    public static String replaceKeyword(String keyword)
    {
        String keyName = keyword.replaceAll("(?:表|信息)", "");
        return keyName;
    }

    static
    {
        javaTypeMap.put("tinyint", "Boolean");
        javaTypeMap.put("smallint", "Integer");
        javaTypeMap.put("mediumint", "Integer");
        javaTypeMap.put("int", "Integer");
        javaTypeMap.put("number", "Integer");
        javaTypeMap.put("integer", "integer");
        javaTypeMap.put("bigint", "Long");
        javaTypeMap.put("float", "Float");
        javaTypeMap.put("double", "Double");
        javaTypeMap.put("decimal", "BigDecimal");
        javaTypeMap.put("bit", "Boolean");
        javaTypeMap.put("char", "String");
        javaTypeMap.put("varchar", "String");
        javaTypeMap.put("varchar2", "String");
        javaTypeMap.put("tinytext", "String");
        javaTypeMap.put("text", "String");
        javaTypeMap.put("mediumtext", "String");
        javaTypeMap.put("longtext", "String");
        javaTypeMap.put("time", "String");
        javaTypeMap.put("date", "Date");
        javaTypeMap.put("datetime", "Date");
        javaTypeMap.put("timestamp", "Date");
    }

    static
    {
        jdbcTypeMap.put("string", "VARCHAR");
        jdbcTypeMap.put("bigdecimal", "DECIMAL");
        jdbcTypeMap.put("boolean", "BOOLEAN");
        jdbcTypeMap.put("long", "BIGINT");
        jdbcTypeMap.put("int", "INTEGER");
        jdbcTypeMap.put("integer", "INTEGER");
        jdbcTypeMap.put("float", "FLOAT");
        jdbcTypeMap.put("double", "DOUBLE");
        //special start
        jdbcTypeMap.put("date", "DATE");
        jdbcTypeMap.put("time", "VARCHAR");
        jdbcTypeMap.put("datetime", "TIMESTAMP");
        //special end
        jdbcTypeMap.put("timestamp", "TIMESTAMP");
        jdbcTypeMap.put("clob", "CLOB");
        jdbcTypeMap.put("blob", "BLOB");
        jdbcTypeMap.put("byte", "TINYINT");
    }

}
